/**
 *@description:
 *@file: resource_manager.cpp
 *@author: snow-tyan
 *@email: zziywang@163.com
 *@date: 31 January 2023
 *@copyright: 2018-2022 AiRiA. All rights reserved.
 */

#include "mygl/util.h"
#include "mygl/resource_manager.h"
#include "mygl/shader.h"
#include "mygl/compute_shader.h"
#include "mygl/texture2d.h"
#include "mygl/yuv_texture2d.h"

namespace mygl {

std::map<std::string, std::shared_ptr<Shader>> ResourceManager::shaders_;
std::map<std::string, std::shared_ptr<ComputeShader>> ResourceManager::compute_shaders_;
std::map<std::string, std::shared_ptr<Texture2D>> ResourceManager::textures_;
std::map<std::string, std::shared_ptr<YuvTexture2D>> ResourceManager::yuv_textures_;

std::shared_ptr<Shader> ResourceManager::LoadShader(const std::string &shader_name,
                                                    const std::string &vertex_path,
                                                    const std::string &fragment_path,
                                                    const std::string &transition_glsl) {
  auto shader = std::make_shared<Shader>(vertex_path, fragment_path, transition_glsl);
  CHECK_MSG(shader->Init() == 0, "Shader Init Failed");
  shaders_[shader_name] = shader;
  return shader;
}

std::shared_ptr<Shader> ResourceManager::GetShader(const std::string &shader_name) {
  return shaders_[shader_name];
}

std::shared_ptr<ComputeShader> ResourceManager::LoadComputeShader(
    const std::string &shader_name, const std::string &compute_path) {
  auto compute_shader = std::make_shared<ComputeShader>(compute_path);
  CHECK_MSG(compute_shader->Init() == 0, "Shader Init Failed");
  compute_shaders_[shader_name] = compute_shader;
  return compute_shader;
}

std::shared_ptr<ComputeShader> ResourceManager::GetComputeShader(
    const std::string &shader_name) {
  return compute_shaders_[shader_name];
}

std::shared_ptr<Texture2D> ResourceManager::LoadTexture(const std::string &texture_name,
                                                        const std::string &image_path,
                                                        bool flip) {
  auto texture2d = std::make_shared<Texture2D>(flip);
  CHECK_MSG(texture2d->Generate(image_path) == 0, "Texture Generate Failed");
  textures_[texture_name] = texture2d;
  return texture2d;
}

std::shared_ptr<Texture2D> ResourceManager::LoadVideoTexture(
    const std::string &texture_name, const std::string &bin_path, int width, int height) {
  auto texture2d = std::make_shared<Texture2D>(width, height);
  CHECK_MSG(0 == texture2d->GenerateVideo(bin_path), "Texture Generate Failed");
  textures_[texture_name] = texture2d;
  return texture2d;
}

std::shared_ptr<Texture2D> ResourceManager::LoadTextureWithoutData(
    const std::string &texture_name, int width, int height) {
  auto texture2d = std::make_shared<Texture2D>();
  texture2d->GenerateWithoutData(width, height);
  textures_[texture_name] = texture2d;
  return texture2d;
}

std::shared_ptr<Texture2D> ResourceManager::GetTexture(const std::string &texture_name) {
  return textures_[texture_name];
}

std::shared_ptr<YuvTexture2D> ResourceManager::LoadYuvTexture(
    const std::string &texture_name, const std::string &bin_path, int width, int height) {
  auto yuv_texture2d = std::make_shared<YuvTexture2D>(width, height);
  CHECK_MSG(0 == yuv_texture2d->Generate(bin_path), "Yuv Texture Init Failed");
  yuv_textures_[texture_name] = yuv_texture2d;
  return yuv_texture2d;
}

std::shared_ptr<YuvTexture2D> ResourceManager::LoadYuvVideoTexture(
    const std::string &texture_name, const std::string &bin_path, int width, int height) {
  auto yuv_texture2d = std::make_shared<YuvTexture2D>(width, height);
  CHECK_MSG(0 == yuv_texture2d->GenerateVideo(bin_path), "Yuv Texture Init Failed");
  yuv_textures_[texture_name] = yuv_texture2d;
  return yuv_texture2d;
}

std::shared_ptr<YuvTexture2D> ResourceManager::GetYuvTexture(
    const std::string &texture_name) {
  return yuv_textures_[texture_name];
}

void ResourceManager::Clear() {
  for (const auto &iter : shaders_) {
    iter.second->DeleteProgram();
  }
  for (const auto &iter : textures_) {
    iter.second->DeleteTextures();
  }
  for (const auto &iter : yuv_textures_) {
    iter.second->DeleteTextures();
  }
}

}  // namespace mygl
